/*
Copyright 2017 yangchong211（github.com/yangchong211）

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package com.yc.video.ui.view;

import ohos.aafwk.ability.Ability;
import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorProperty;
import ohos.agp.colors.RgbColor;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.components.LayoutScatter;
import ohos.agp.components.ProgressBar;
import ohos.agp.components.Slider;
import ohos.agp.components.StackLayout;
import ohos.agp.components.Text;
import ohos.agp.components.element.ShapeElement;
import ohos.app.Context;

import com.yc.video.ResourceTable;
import com.yc.video.bridge.ControlWrapper;
import com.yc.video.config.ConstantKeys;
import com.yc.video.config.VideoPlayerConfig;
import com.yc.video.tool.PlayerUtils;

/**
 * 底部控制栏视图
 * 用于普通播放器
 *
 * @since 2021-05-10
 */
public class CustomBottomView extends StackLayout implements InterControlView,
    Component.ClickedListener, Slider.ValueChangedListener {
    private static final int NUM_255 = 255;
    private static final int UNSPECIFIED = -1;
    private static final int LANDSCAPE = 0;
    private static final int PORTRAIT = 1;
    private static final int FOLLOWRECENT = 3;
    private static final int SCREEN_ORIENTATION_REVERSE_LANDSCAPE = 8; // 没找到对应的值，暂时模拟成

    protected ControlWrapper mControlWrapper;
    private Context mContext;
    private DirectionalLayout mLlBottomContainer;
    private Component mIvPlay;
    private Text mTvCurrTime;
    private Slider mSeekBar;
    private Text mTvTotalTime;
    private Component mIvFullscreen;
    private ProgressBar mPbBottomProgress;
    private boolean mIsDragging;
    private boolean mIsShowBottomProgress = true;

    private OnToastListener listener;

    /**
     * CustomBottomView
     *
     * @param context context
     */
    public CustomBottomView(Context context) {
        super(context);
        init(context);
    }

    /**
     * CustomBottomView
     *
     * @param context context
     * @param attrs attrs
     */
    public CustomBottomView(Context context, AttrSet attrs) {
        super(context, attrs);
        init(context);
    }

    /**
     * CustomBottomView
     *
     * @param context context
     * @param attrs attrs
     * @param defStyleAttr defStyleAttr
     */
    public CustomBottomView(Context context, AttrSet attrs, String defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context);
    }

    private void init(Context context) {
        this.mContext = context;
        setVisibility(HIDE);
        Component view = LayoutScatter.getInstance(getContext()).parse(getLayoutId(), this, true);
        initFindViewById(view);
        initListener();
    }

    private void initFindViewById(Component view) {
        mLlBottomContainer = (DirectionalLayout) view.findComponentById(ResourceTable.Id_ll_bottom_container);
        mIvPlay = view.findComponentById(ResourceTable.Id_iv_play);
        mTvCurrTime = (Text) view.findComponentById(ResourceTable.Id_tv_curr_time);
        mSeekBar = (Slider) view.findComponentById(ResourceTable.Id_seekBar);
        mTvTotalTime = (Text) view.findComponentById(ResourceTable.Id_tv_total_time);
        mIvFullscreen = view.findComponentById(ResourceTable.Id_iv_fullscreen);
        mPbBottomProgress = (ProgressBar) view.findComponentById(ResourceTable.Id_pb_bottom_progress);

        ShapeElement shapeElement = new ShapeElement();
        shapeElement.setRgbColor(new RgbColor(NUM_255, NUM_255, NUM_255));
        shapeElement.setCornerRadius(6.0F);
        mSeekBar.setViceProgressElement(shapeElement);
    }

    private void initListener() {
        mIvFullscreen.setClickedListener(this);
        mSeekBar.setValueChangedListener(this);
        mIvPlay.setClickedListener(this);
    }

    @Override
    public void onClick(Component v) {
        if (v == mIvFullscreen) {
            mIvFullscreen.setSelected(!mIvFullscreen.isSelected());
            toggleFullScreen();
        } else if (v == mIvPlay) {
            mControlWrapper.togglePlay();
        }
    }

    protected int getLayoutId() {
        return ResourceTable.Layout_custom_video_player_bottom;
    }

    /**
     * 是否显示底部进度条，默认显示
     *
     * @param isShow isShow
     */
    public void showBottomProgress(boolean isShow) {
        mIsShowBottomProgress = isShow;
    }

    @Override
    public void attach(ControlWrapper controlWrapper) {
        mControlWrapper = controlWrapper;
    }

    @Override
    public Component getView() {
        return this;
    }

    @Override
    public void onVisibilityChanged(boolean isVisible, Animator anim) {
        if (isVisible) {
            mLlBottomContainer.setVisibility(VISIBLE);
            if (anim != null) {
                if (anim instanceof AnimatorProperty) {
                    ((AnimatorProperty) anim).setTarget(mLlBottomContainer);
                    anim.start();
                }
            }
            if (mIsShowBottomProgress) {
                mPbBottomProgress.setVisibility(HIDE);
            }
        } else {
            mLlBottomContainer.setVisibility(HIDE);
            if (anim != null) {
                if (anim instanceof AnimatorProperty) {
                    ((AnimatorProperty) anim).setTarget(mLlBottomContainer);
                    anim.start();
                }
            }
            if (mIsShowBottomProgress) {
                mPbBottomProgress.setVisibility(VISIBLE);
                mPbBottomProgress.createAnimatorProperty().alphaFrom(0).alpha(1).setDuration(300).start();
            }
        }
    }

    @Override
    public void onPlayStateChanged(int playState) {
        switch (playState) {
            case ConstantKeys.CurrentState.STATE_IDLE:
            case ConstantKeys.CurrentState.STATE_BUFFERING_PLAYING:
                setVisibility(HIDE);
                mPbBottomProgress.setProgressValue(0);
                mPbBottomProgress.setViceProgress(0);
                mSeekBar.setProgressValue(0);
                mSeekBar.setViceProgress(0);
                break;
            case ConstantKeys.CurrentState.STATE_START_ABORT:
            case ConstantKeys.CurrentState.STATE_PREPARING:
            case ConstantKeys.CurrentState.STATE_PREPARED:
            case ConstantKeys.CurrentState.STATE_ERROR:
            case ConstantKeys.CurrentState.STATE_ONCE_LIVE:
                setVisibility(HIDE);
                mSeekBar.setMaxValue((int) mControlWrapper.getDuration());
                mPbBottomProgress.setMaxValue((int) mControlWrapper.getDuration());
                break;
            case ConstantKeys.CurrentState.STATE_PLAYING:
                mIvPlay.setSelected(true);
                if (mIsShowBottomProgress) {
                    if (mControlWrapper.isShowing()) {
                        mPbBottomProgress.setVisibility(HIDE);
                        mLlBottomContainer.setVisibility(VISIBLE);
                    } else {
                        mLlBottomContainer.setVisibility(HIDE);
                        mPbBottomProgress.setVisibility(VISIBLE);
                    }
                } else {
                    mLlBottomContainer.setVisibility(HIDE);
                }
                setVisibility(VISIBLE);
                mControlWrapper.startProgress(); // 开始刷新进度
                break;
            case ConstantKeys.CurrentState.STATE_PAUSED:
                mIvPlay.setSelected(false);
                break;
            case ConstantKeys.CurrentState.STATE_BUFFERING_PAUSED:
            case ConstantKeys.CurrentState.STATE_COMPLETED:
                mIvPlay.setSelected(mControlWrapper.isPlaying());
                break;
            default:
                break;
        }
    }

    @Override
    public void onPlayerStateChanged(int playerState) {
        switch (playerState) {
            case ConstantKeys.PlayMode.MODE_NORMAL:
                mIvFullscreen.setSelected(false);
                break;
            case ConstantKeys.PlayMode.MODE_FULL_SCREEN:
                mIvFullscreen.setSelected(true);
                break;
        }

        Ability activity = PlayerUtils.scanForActivity(mContext);
        if (activity != null && mControlWrapper.hasCutout()) {
            int orientation = activity.getDisplayOrientation();
            int cutoutHeight = mControlWrapper.getCutoutHeight();
            if (orientation == PORTRAIT) {
                mLlBottomContainer.setPadding(0, 0, 0, 0);
                mPbBottomProgress.setPadding(0, 0, 0, 0);
            } else if (orientation == LANDSCAPE) {
                mLlBottomContainer.setPadding(cutoutHeight, 0, 0, 0);
                mPbBottomProgress.setPadding(cutoutHeight, 0, 0, 0);
            } else if (orientation == SCREEN_ORIENTATION_REVERSE_LANDSCAPE) {
                mLlBottomContainer.setPadding(0, 0, cutoutHeight, 0);
                mPbBottomProgress.setPadding(0, 0, cutoutHeight, 0);
            }
        }
    }

    /**
     * 刷新进度回调，子类可在此方法监听进度刷新，然后更新ui
     *
     * @param duration 视频总时长
     * @param position 视频当前时长
     */
    @Override
    public void setProgress(int duration, int position) {
        if (mIsDragging) {
            return;
        }

        if (mSeekBar != null) {
            if (duration > 0) {
                mSeekBar.setEnabled(true);
                int pos = (int) (position * 1.0 / duration * mSeekBar.getMax());
                mSeekBar.setProgressValue(pos);
                mPbBottomProgress.setProgressValue(pos);
            } else {
                mSeekBar.setEnabled(false);
            }

            int percent = mControlWrapper.getBufferedPercentage();
            if (percent >= 95) {
                // 解决缓冲进度不能100%问题
                mSeekBar.setViceProgress(mPbBottomProgress.getMax());
                mPbBottomProgress.setViceProgress(mPbBottomProgress.getMax());
            } else {
                mSeekBar.setViceProgress(position * 2);
                mPbBottomProgress.setViceProgress(position * 2);
            }
        }

        if (mTvTotalTime != null) {
            mTvTotalTime.setText(PlayerUtils.formatTime(duration));
        }
        if (mTvCurrTime != null) {
            mTvCurrTime.setText(PlayerUtils.formatTime(position));
        }

        if (VideoPlayerConfig.newBuilder().build().mIsShowToast) {
            long time = VideoPlayerConfig.newBuilder().build().mShowToastTime;
            if (time <= 0) {
                time = 5;
            }
            long currentPosition = mControlWrapper.getCurrentPosition();
            if (duration - currentPosition < 2 * time * 1000) {
                // 当前视频播放到最后3s时，弹出toast提示：即将自动为您播放下一个视频。
                if ((duration - currentPosition) / 1000 % 60 == time) {
                    if (listener != null) {
                        listener.showToastOrDialog();
                    }
                }
            }
        }
    }

    @Override
    public void onLockStateChanged(boolean isLocked) {
        onVisibilityChanged(!isLocked, null);
    }

    /**
     * 横竖屏切换
     */
    private void toggleFullScreen() {
        Ability activity = PlayerUtils.scanForActivity(getContext());
        mControlWrapper.toggleFullScreen(activity);
    }

    public void setListener(OnToastListener listener) {
        this.listener = listener;
    }

    @Override
    public void onProgressUpdated(Slider slider, int progress, boolean fromUser) {
        if (!fromUser) {
            return;
        }
        if (mTvCurrTime != null) {
            String str = PlayerUtils.formatTime(progress);
            mTvCurrTime.setText(str);
        }
    }

    @Override
    public void onTouchStart(Slider slider) {
        mIsDragging = true;
        mControlWrapper.stopProgress();
        mControlWrapper.stopFadeOut();
    }

    @Override
    public void onTouchEnd(Slider slider) {
        mControlWrapper.seekTo(slider.getProgress());
        mIsDragging = false;
        mControlWrapper.startProgress();
        mControlWrapper.startFadeOut();
    }

    public boolean isDragging() {
        return mIsDragging;
    }

    public Component getIvFullScreen() {
        return mIvFullscreen;
    }

    /**
     * OnToastListener
     */
    public interface OnToastListener {
        /**
         * showToastOrDialog
         */
        void showToastOrDialog();
    }
}
